﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Domain.Core;
using Domain.Core.Specification;
using Infrastructure.CrossCutting.Caching;
using Infrastructure.Data.Core;

namespace Application.Core.EntityService
{
    public class BaseService<TEntity, TEntityKey> : IBaseService<TEntity, TEntityKey> where TEntity : class
    {
        private readonly IRepository<TEntity, TEntityKey> _repository;
        private readonly ICache _cache;
        public BaseService(IRepository<TEntity, TEntityKey> repository, ICache cache)
        {
            _repository = repository;
            _cache = cache;
        }
        public void Add(TEntity item)
        {
            _repository.Add(item);
        }

        public void Remove(TEntity item)
        {
            _repository.Remove(item);
        }

        public void Modify(TEntity item)
        {
            _repository.Modify(item);
        }

        public void TrackItem(TEntity item)
        {
            _repository.TrackItem(item);
        }

        public void Merge(TEntity persisted, TEntity current)
        {
            _repository.Merge(persisted, current);
        }

        public List<TEntity> GetAll(string cacheName = null, Expression<Func<TEntity, object>> include = null)
        {
            var entities = _repository.GetAll();
            if (!string.IsNullOrEmpty(cacheName))
            {
                var cacheItemConfig = new CacheItemConfig(new CacheKey(cacheName), new TimeSpan(0, 30, 0));
                var entityResults = _cache.TryGet<List<TEntity>>(cacheItemConfig.CacheKey);
                if (entityResults == null)
                {
                    entityResults = include == null ? entities.ToList() : entities.Include(include).ToList();
                    _cache.Set(cacheItemConfig, entityResults);
                }
                return entityResults;
            }
            return entities.ToList();
        }

        public IEnumerable<TEntity> AllMatching(ISpecification<TEntity> specification)
        {
            return _repository.AllMatching(specification);
        }

        public List<TEntity> GetFiltered(Expression<Func<TEntity, bool>> filter, string cacheName = null, Expression<Func<TEntity, object>> include = null)
        {
            var entities = _repository.GetFiltered(filter);
            if (!string.IsNullOrEmpty(cacheName))
            {
                var cacheItemConfig = new CacheItemConfig(new CacheKey(cacheName), new TimeSpan(0, 30, 0));
                var entityResults = _cache.TryGet<List<TEntity>>(cacheItemConfig.CacheKey);
                if (entityResults == null)
                {
                    entityResults = include == null ? entities.ToList() : entities.Include(include).ToList();
                    _cache.Set(cacheItemConfig, entityResults);
                }
                return entityResults;
            }
            return entities.ToList();
        }

    }
}
